package sunyu.controller.shiro;

import org.apache.shiro.authz.annotation.Logical;
import org.apache.shiro.authz.annotation.RequiresAuthentication;
import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.slf4j.Logger;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.WebDataBinder;
import org.springframework.web.bind.annotation.*;
import sunyu.controller.common.CommonController;
import sunyu.controller.shiro.tools.ResourceTools;
import sunyu.kit.common.LogKit;
import sunyu.kit.common.StringKit;
import sunyu.mapper.shiro.pojo.Resource;
import sunyu.service.shiro.ResourceService;

import java.util.*;

/**
 * 资源Controller
 *
 * @author 孙宇
 */
@Controller
@RequestMapping("/shiro/resource")
public class ResourceController extends CommonController {

    private static final Logger logger = LogKit.getLogger();

    @javax.annotation.Resource(name = "resourceService")
    private ResourceService resourceService;

    /**
     * 表单name前缀绑定
     * <p>
     * 提交表单的name需要resource.xxx
     *
     * @param binder
     */
    @InitBinder("resource")
    public void initBinderResource(WebDataBinder binder) {
        binder.setFieldDefaultPrefix("resource.");
    }

    /**
     * 跳转到列表页面
     *
     * @param model
     * @return
     */
    @RequestMapping(value = "/list", method = RequestMethod.GET)
    @RequiresAuthentication//验证是否登录，等同于subject.isAuthenticated()
    @RequiresPermissions(value = {"shiro:resource:list"}, logical = Logical.AND)//验证是否有权限
    public String list(Model model) {
        ResourceTools.getResourceTree(model, resourceService);

        return "/shiro/resource/list";
    }

    /**
     * 跳转到新增页面
     *
     * @param model
     * @return
     */
    @RequestMapping(value = "/insert", method = RequestMethod.GET)
    @RequiresAuthentication//验证是否登录，等同于subject.isAuthenticated()
    @RequiresPermissions(value = {"shiro:resource:insert"}, logical = Logical.AND)//验证是否有权限
    public String insert(Model model) {
        return insertPage(model);
    }

    /**
     * 跳转到insert页面
     *
     * @param model
     * @return
     */
    private String insertPage(Model model) {
        model.addAttribute("action", "insert");//告诉前台页面的form，准备调用insert操作

        ResourceTools.getResourceTree(model, resourceService);

        return "/shiro/resource/form";
    }

    /**
     * 新增
     *
     * @param resource
     * @return
     */
    @RequestMapping(value = "/insert", method = RequestMethod.POST)
    @RequiresAuthentication//验证是否登录，等同于subject.isAuthenticated()
    @RequiresPermissions(value = {"shiro:resource:insert"}, logical = Logical.AND)//验证是否有权限
    public String insert(@ModelAttribute("resource") Resource resource,
                         Model model) {
        Map<String, Object> params = new HashMap<String, Object>() {{
            put("permission", resource.getPermission());
        }};
        if (resourceService.count(params) > 0) {
            model.addAttribute("errMsg", "资源许可编号已存在！");
            return insertPage(model);
        }

        resource.setId(UUID.randomUUID().toString());
        resource.setCreated(new Date());
        resource.setModified(resource.getCreated());

        fixLevels(resource);

        resourceService.insert(resource);

        return "redirect:/shiro/resource/list";
    }

    /**
     * 通过选择的父级资源，自动修复本级的级别
     *
     * @param resource
     */
    private void fixLevels(@ModelAttribute("resource") Resource resource) {
        if (StringKit.isNotBlank(resource.getPid())) {//说明选择了父级资源
            Resource pr = resourceService.selectById(resource.getPid());
            resource.setLevels(pr.getLevels() + 1);//把当前资源的级别+1
        } else {
            resource.setLevels(0);//没有选择父资源，那么当前资源的级别为0
            resource.setPid(null);
        }
    }


    /**
     * 删除
     *
     * @param id
     * @return
     */
    @RequestMapping(value = "/delete/{id}")
    @RequiresAuthentication
    @RequiresPermissions(value = {"shiro:resource:delete"})
    public String delete(@PathVariable("id") String id) {
        resourceService.delete(id);
        return "redirect:/shiro/resource/list";
    }

    /**
     * 跳转到编辑页面
     *
     * @param model
     * @param id
     * @return
     */
    @RequestMapping(value = "/update/{id}", method = RequestMethod.GET)
    @RequiresAuthentication
    @RequiresPermissions(value = {"shiro:resource:update"})
    public String update(Model model,
                         @PathVariable("id") String id) {
        Resource resource = resourceService.selectById(id);
        return updatePage(model, resource);
    }

    /**
     * 跳转到修改页面
     *
     * @param model
     * @param resource
     * @return
     */
    private String updatePage(Model model,
                              Resource resource) {
        model.addAttribute("resource", resource);
        model.addAttribute("action", "update");//告诉前台页面的form，准备调用update操作

        ResourceTools.getResourceTree(model, resourceService);

        return "/shiro/resource/form";
    }

    /**
     * 更新
     *
     * @param resource
     * @return
     */
    @RequestMapping(value = "/update", method = RequestMethod.POST)
    @RequiresAuthentication
    @RequiresPermissions(value = {"shiro:resource:update"})
    public String update(@ModelAttribute("resource") Resource resource,
                         Model model) {
        Map<String, Object> params;

        if (StringKit.isNotBlank(resource.getPid()) && resource.getId().equals(resource.getPid())) {//如果选择的父级资源与自己本身id相同，说明设置错误
            model.addAttribute("errMsg", "父级资源不可以选择自己！");
            return updatePage(model, resource);
        }

        if (pidIsChild(model, resource, resource.getId())) {//这里需要判断，要设置的父级资源是否是自己的子节点
            model.addAttribute("errMsg", "父级资源不可以设置为自己的下属资源！");
            return updatePage(model, resource);
        }

        params = new HashMap<String, Object>() {{
            put("permission", resource.getPermission());
        }};
        List<Resource> l = resourceService.select(null, params);
        if (l != null && l.size() > 0) {
            if (!l.get(0).getId().equals(resource.getId())) {//如果数据库里面拥有当前资源许可编号的对象的id与要更新的id不同，说明这个编号已经被别人使用了。
                model.addAttribute("errMsg", "资源许可编号已存在！");
                return updatePage(model, resource);
            }
        }

        resource.setModified(new Date());

        fixLevels(resource);

        resourceService.update(resource);

        return "redirect:/shiro/resource/list";
    }

    /**
     * 判断要设置的pid是不是自己子节点
     *
     * @param model
     * @param resource
     * @param currentId
     * @return
     */
    private Boolean pidIsChild(Model model,
                               Resource resource,
                               String currentId) {
        if (StringKit.isNotBlank(resource.getPid())) {
            Resource targetParent = resourceService.selectById(resource.getPid());
            if (targetParent.getId().equals(currentId)) {
                return true;
            } else {
                return pidIsChild(model, targetParent, currentId);
            }
        } else {
            return false;
        }
    }
}
